﻿using System;
using System.Drawing;
using System.Windows.Forms;

namespace CloudDetector.RasterMap
{
    /// <summary>
    /// Műholdfelvételeket tároló osztály
    /// </summary>
    public class Map
    {
        #region Fields
        private Image mapImage; 
        private Double zoomLevel; 
        private PictureBox zoomDisplay; 
        private PictureBox fullDisplay;
        private Int32 centerX;
        private Int32 centerY;
        private Int32 step;
        #endregion

        #region Properties

        public PictureBox ZoomDisplay 
        {
            set { zoomDisplay = value; Draw(); }
            get { return zoomDisplay; }
        }

        public PictureBox FullDisplay
        {
            set 
            { 
                fullDisplay = value; 
                Draw(); 
            }
            get { return fullDisplay; }
        }

        public Int32 NavZoomLevel
        {
            set { zoomLevel = Convert.ToSingle(Math.Sqrt(Convert.ToSingle(value) / 100)); Draw(); }
            get { return Convert.ToInt32(zoomLevel * 100); }
        }

        public double Zoomlevel
        {
            get { return zoomLevel; }
        }

        public Int32 MoveStep
        {
            set
            {
                step = (value < 1) ? 1 : value;
            }
            get { return step; }
        }
        
        #endregion

        #region Constructors

        /// <summary>
        /// Konstruktor a megadott fájl név szerinti betöltéséhez.
        /// </summary>
        /// <param name="file_name">Fájlnév.</param>
        public Map(String file_name)
        {
            mapImage = new Bitmap(file_name);
            step = (mapImage.Width < mapImage.Height) ? mapImage.Width / 10 : mapImage.Height / 10;
            Reset();
        }

        /// <summary>
        /// Konstruktor a program által generált képek betöltéséhez.
        /// </summary>
        /// <param name="Bm">Bitmap kép</param>
        public Map(Bitmap Bm)
        {
            mapImage = Bm;
            step = (mapImage.Width < mapImage.Height) ? mapImage.Width / 10 : mapImage.Height / 10;
            Reset();
        }

        public void Reset()
        {
            zoomLevel = 1;
            centerX = mapImage.Width / 2;
            centerY = mapImage.Height / 2;
            Draw();
        }

        public void Refresh()
        {
            Draw();
        }
        
        #endregion

        #region Map moving

        public void Left()
        {
            if (zoomDisplay != null)
            {
                if (centerX - zoomDisplay.Width / 2 >= step / zoomLevel)
                    centerX -= Convert.ToInt32(step / zoomLevel);
                else
                    centerX = Convert.ToInt32(zoomDisplay.Width / 2 / zoomLevel);
            }
            Draw();
        }

        public void Right()
        {
            if (zoomDisplay != null)
            {
                if (centerX + zoomDisplay.Width / 2 / zoomLevel < mapImage.Width - step / zoomLevel )
                    centerX += Convert.ToInt32(step / zoomLevel);
                else
                    centerX = Convert.ToInt32(mapImage.Width - Math.Ceiling(zoomDisplay.Width / 2 / zoomLevel));
            }
            Draw();
        }

        public void Up()
        {
            if (zoomDisplay != null)
            {
                if (centerY - zoomDisplay.Height / 2 >= step / zoomLevel)
                    centerY -= Convert.ToInt32(step / zoomLevel);
                else
                    centerY = Convert.ToInt32(zoomDisplay.Height / 2 / zoomLevel);
            }
            Draw();
        }
        
        public void Down()
        {
            if (zoomDisplay != null)
            {
                if (centerY + zoomDisplay.Height / 2 / zoomLevel < mapImage.Height - step / zoomLevel)
                    centerY += Convert.ToInt32(step / zoomLevel);
                else
                    centerY = Convert.ToInt32(mapImage.Height - Math.Ceiling(zoomDisplay.Height / 2 / zoomLevel));
            }
            Draw();
        }

        public void Move(Int32 x, Int32 y)
        { 
            if (zoomDisplay != null)
            {
                if ((centerX * zoomLevel + x - zoomDisplay.Width / 2) >= 0 && (centerX * zoomLevel + x + zoomDisplay.Width / 2) < mapImage.Width * zoomLevel)
                    centerX += x;
                if ((centerY * zoomLevel + y - zoomDisplay.Height / 2) >= 0 && (centerY * zoomLevel + y + zoomDisplay.Height / 2) < mapImage.Height * zoomLevel)
                    centerY += y;
            }
            Draw();
        }
        
        #endregion

        private void Draw()
        {
            if (zoomDisplay != null)
            {
                if (zoomDisplay.Image != null)
                    zoomDisplay.Image.Dispose();

                // létrehozunk egy új képet a nagyított nézethez:
                Bitmap zoomed_map_image = new Bitmap((Int32)(Math.Ceiling(mapImage.Width * zoomLevel)), (Int32)(Math.Ceiling(mapImage.Height * zoomLevel)));

                // a rajzolást nem a képernyőn végezzük, hanem a háttérben:
                Graphics zoomed_map_graphics = Graphics.FromImage((Image)zoomed_map_image);

                // zoomoláshoz interpoláció:
                zoomed_map_graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; // a zoomoláshoz interpolálunk
                zoomed_map_graphics.DrawImage(mapImage, 0, 0, zoomed_map_image.Width, zoomed_map_image.Height);

                // megfelelő képrészlet kivágása:
                Int32 start_x = (centerX * zoomLevel < zoomDisplay.Width / 2) ? 0 : Convert.ToInt32(centerX * zoomLevel - zoomDisplay.Width / 2);
                Int32 start_y = (centerY * zoomLevel < zoomDisplay.Height / 2) ? 0 : Convert.ToInt32(centerY * zoomLevel - zoomDisplay.Height / 2);
                Int32 size_x = (start_x + zoomDisplay.Width < zoomed_map_image.Width) ? zoomDisplay.Width : zoomed_map_image.Width - start_x;
                Int32 size_y = (start_y + zoomDisplay.Height < zoomed_map_image.Height) ? zoomDisplay.Height : zoomed_map_image.Height - start_y;

                zoomDisplay.Image = zoomed_map_image.Clone(new Rectangle(start_x, start_y, size_x, size_y), zoomed_map_image.PixelFormat);
                zoomed_map_image.Dispose();

                if (fullDisplay != null)
                {
                    // méretarányok meghatározása:
                    Double scale = ((Double)mapImage.Width / fullDisplay.Width > (Double)mapImage.Height / fullDisplay.Height) ? (Double)mapImage.Width / fullDisplay.Width : (Double)mapImage.Height / fullDisplay.Height;
                    Int32 t_start_x = Convert.ToInt32(fullDisplay.Width - Math.Ceiling(mapImage.Width / scale)) / 2;
                    Int32 t_start_y = Convert.ToInt32(fullDisplay.Height - Math.Ceiling(mapImage.Height / scale)) / 2;
                    Int32 t_size_x = Convert.ToInt32(mapImage.Width / scale);
                    Int32 t_size_y = Convert.ToInt32(mapImage.Height / scale);

                    // új kép létrehozása a kijelölőnégyzethez:
                    Image full_map_image = new Bitmap(fullDisplay.Width, fullDisplay.Height);

                    // a rajzolást nem a képernyőn végezzük, hanem a háttérben:
                    Graphics full_map_graphics = Graphics.FromImage(full_map_image);
                    full_map_graphics.FillRectangle(Brushes.White, 0, 0, fullDisplay.Width, fullDisplay.Height);
                    full_map_graphics.DrawImage(mapImage, t_start_x, t_start_y, t_size_x, t_size_y);
                    
                    // kijelölőnégyzet rajzolása:
                    full_map_graphics.DrawRectangle(new Pen(Color.Red),
                                     Convert.ToSingle(t_start_x + start_x / scale / zoomLevel),
                                     Convert.ToSingle(t_start_y + start_y / scale / zoomLevel),
                                     Convert.ToSingle(size_x / zoomLevel / scale - 1),
                                     Convert.ToSingle(size_y / zoomLevel / scale - 1));
                    full_map_graphics.Dispose();

                    // kitesszük a képet:
                    fullDisplay.CreateGraphics().DrawImage(full_map_image, 0, 0);
                    full_map_image.Dispose();
                }
            }
        }

    }
}
